package com.ruoyi.common.utils;

import com.ruoyi.common.enums.DurianRedisKeysType;
import com.ruoyi.common.exception.ServiceException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.data.geo.*;
import org.springframework.data.redis.connection.RedisGeoCommands;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Component;

import javax.annotation.Resource;
import java.util.List;
import java.util.Map;

/**
 * redis GEO 工具类
 */
@Component
public class RedisGeoUtils {

    @Resource
    private StringRedisTemplate stringRedisTemplate;

    private static final Logger logger = LoggerFactory.getLogger("RedisGeo");


    /**
     * 添加坐标geoAdd
     *
     * @return
     */
    public void geoAdd(String key, Map<String, Point> map) {
        if (map == null || map.size() == 0) {
            throw new ServiceException("初始化地图参数为空，请校验参数");
        }
        stringRedisTemplate.opsForGeo().add(key, map);
    }

    /**
     * 删除坐标geo
     *
     * @return
     */
    public void geoDel(String key, String member) {
        if (StringUtils.isEmpty(key) || StringUtils.isEmpty(member)) {
            throw new ServiceException("删除坐标参数为空，请校验参数");
        }
        stringRedisTemplate.opsForGeo().remove(key, member);
    }

    /**
     * 获取经纬度坐标geopos
     *
     * @param member
     * @return
     */
    public Point position(String member) {
        //获取经纬度坐标
        List<Point> list = stringRedisTemplate.opsForGeo().position(DurianRedisKeysType.ADDRESS.getKey(), member);
        return list.get(0);
    }

    /**
     * 获取经纬度生成的base32编码值geohash
     *
     * @param member
     * @return
     */
    public String hash(String member) {
        //geohash算法生成的base32编码值
        List<String> list = stringRedisTemplate.opsForGeo().hash(DurianRedisKeysType.ADDRESS.getKey(), member);
        return list.get(0);
    }

    /**
     * 获取两个给定位置之间的距离
     *
     * @param key
     * @param member1
     * @param member2
     * @return
     */
    public Distance distance(String key, String member1, String member2) {
        //获取两个给定位置之间的距离
        Distance distance = stringRedisTemplate.opsForGeo().distance(key, member1, member2,
                RedisGeoCommands.DistanceUnit.KILOMETERS);
        return distance;
    }

    /**
     * 通过经度纬度查找附近的
     *
     * @param mapX   横坐标
     * @param mapY   纵坐标
     * @param key    地点/人/车
     * @param radius 半径
     * @param limit  数量
     * @return
     */
    public GeoResults radiusByxy(String mapX, String mapY, String key, Integer radius, Integer limit) {
        if (radius <= 0) {
            radius = 1;
        }
        Circle circle = new Circle(Double.parseDouble(mapX), Double.parseDouble(mapY), 1000 * radius);
        RedisGeoCommands.GeoRadiusCommandArgs args = RedisGeoCommands.GeoRadiusCommandArgs
                .newGeoRadiusArgs()
                .includeDistance()
                .includeCoordinates()
                .sortAscending()
                .limit(limit);
        GeoResults<RedisGeoCommands.GeoLocation<String>> geoResults =
                stringRedisTemplate.opsForGeo().radius(key, circle, args);
        return geoResults;
    }

    /**
     * 通过地方查找附近
     *
     * @param name
     * @return
     */
    public GeoResults radiusByMember(String name) {

        //通过地方查找附近
        //获取经纬度坐标
        List<Point> list = stringRedisTemplate.opsForGeo().position(DurianRedisKeysType.ADDRESS.getKey(), name);
        Point point = list.get(0);

        //通过经度，纬度查找附近的,北京王府井位置116.418017,39.914402
        Circle circle = new Circle(point.getX(), point.getY(), Metrics.KILOMETERS.getMultiplier());
        // 返回50条
        RedisGeoCommands.GeoRadiusCommandArgs args = RedisGeoCommands.GeoRadiusCommandArgs.newGeoRadiusArgs().includeDistance().includeCoordinates().sortDescending().limit(50);

        GeoResults<RedisGeoCommands.GeoLocation<String>> geoResults = stringRedisTemplate.opsForGeo().radius(DurianRedisKeysType.ADDRESS.getKey(), circle, args);

        return geoResults;
    }

}
